/*
* ============================================================================
*  Name        : sea_parser.h
*  Part of     : Finite state machine framework
*  Description : State machine parser
*  Version     : %version: %
*  
*
* ============================================================================
*/
#if !defined( __sea_sm_parser_h__ )
#define __sea_sm_parser_h__

#include "sea.h"

/**
 * @file sea_parser.h
 * @brief
 * State Machine source code compiler <br>
 * @ref sea::Parser 
 *
 * @ingroup StateMachineFramework
 */

namespace sea
{
    /**
     * @class Parser sea_parser.h "sea_parser.h"
     * @brief
     *  State machine source code compiler. \b INTERNAL \b API. 
     *
     * @ingroup StateMachineFramework
     */
    class Parser : public StateMachine
    {
        friend class StateMachine;
        friend class Manager;

    private:

        // State machine input format
        enum Type
        {
            eFile,
            eString,
            eBinary
        };

        /**
         * State machine header offsets
         */
        enum StateMachineHeader
        {
            eSize = 0,
            eReserved01,
            eReserved02,
            eExecMode,
            eNumberOfStates,
            eInitialStateIndex,
            eExceptionStateIndex
        };

        /**
         * State header offsets
         */
        enum StateHeader
        {
            eHeartBeatInterval = 0,
            eHeartBeatsNumber,
            eNumberOfRecords,
            eEventRecords
        };

        /**
         * Event Record offsets
         */
        enum EventRecord
        {
            eEvent = 0,
            eAction,
            eNextState
        };

        /** 
         * Ctor
         */
        Parser( );

        /** 
         * Parse the source code
         *
         * @param state_machine State machine instance
         * @param str Source code to compile
         * @param type Execution type @ref sea::Type
         *
         * @return ExecCode* Pointer to compiled state machine
         */
        ExecCode* exec( StateMachine* state_machine, const char* str, Type type );

        /** 
         * Parse precompiled code. Resolve state transitions - Index to Abs offset
         *
         * @param state_machine State machine instance
         * @param raw_array State machine in binary format
         *
         * @return ExecCode* Pointer to compiled state machine
         */
        ExecCode* exec( StateMachine* state_machine, BinCode raw_array );

        /*  0 */ ACT( Parser, init );
        /*  1 */ ACT( Parser, ParseBinarySm );
        /*  2 */ ACT( Parser, readString );
        /*  3 */ ACT( Parser, getLiteral );
        /*  4 */ ACT( Parser, createStateMachine );
        /*  5 */ ACT( Parser, storeExecMode );
        /*  6 */ ACT( Parser, createState );
        /*  7 */ ACT( Parser, storeHeartBeatInterval );
        /*  8 */ ACT( Parser, storeHeartBeats );
        /*  9 */ ACT( Parser, createEventRecord );
        /* 10 */ ACT( Parser, storeEvent );
        /* 11 */ ACT( Parser, storeAction );
        /* 12 */ ACT( Parser, storeNextState );
        /* 13 */ ACT( Parser, endOfState );
        /* 14 */ ACT( Parser, complete );
        /* 15 */ ACT( Parser, error );
        /* 16 */ ACT( Parser, resolveNextStates );

        /*  0 */ EVENT_INT( Parser, Ev_Int_InitOk );
        /*  1 */ EVENT_INT( Parser, Ev_Int_InitBinaryOk );
        /*  2 */ EVENT_INT( Parser, Ev_Int_InitFailed );
        /*  3 */ EVENT_INT( Parser, Ev_Int_ParseError );
        /*  4 */ EVENT_INT( Parser, Ev_Int_Eol );
        /*  5 */ EVENT_INT( Parser, Ev_Int_Eof );
        /*  6 */ EVENT_INT( Parser, Ev_Int_NotEmptyString );
        /*  7 */ EVENT_INT( Parser, Ev_Int_GotNumber );
        /*  8 */ EVENT_INT( Parser, Ev_Int_GotName );
        /*  9 */ EVENT_INT( Parser, Ev_Int_GotOpenBracket );
        /* 10 */ EVENT_INT( Parser, Ev_Int_GotCloseBracket );
        /* 11 */ EVENT_INT( Parser, Ev_Int_ResolveOk );
        /* 12 */ EVENT_INT( Parser, Ev_Int_ParseWarning );

        /** 
         * Make the compiled state machine as sharable object
         *
         * @return ExecCode* Pointer to compiled state machine
         */
        ExecCode* finalize( );

        /** 
         * Reset internal data to prepare for another compilation
         */
        void reset( );

    private:
        
        sea::Error m_error_code;                    ///< Parsing error code
        Parser::Type m_type;                        ///< Input type 
        sea::BinCode m_raw_array;                   ///< Binary/raw state machine notation
        sea::String m_the_string;                   ///< Declarative/String state machine notation
        sea::String m_file_name;                    ///< Declarative/File state machine notation

        char* m_literal_buffer;
        char* m_current_ptr;
        FILE* m_file;

        StateMachine* m_state_machine;              ///< State machine object we are parsing for
        map< i::Offset, String > m_nsl2state_name;  ///< For the second pass keep next state locations(nsl)
                                                    ///< and corresponding names
        map< string, i::Offset > m_state_name2offset;///< State name to offset in the binary buffer
        i::uint32 m_offset;                         ///< Offset in raw buffer
        int m_state_index;                          ///< Index of the parsed state
        int m_event_record_counter;                 ///< Counter of the current state
        i::uint32 m_current_state_offset;           ///< Store offset of the current state
        long m_file_size;                           ///< source file size

        std::vector< int > m_rt_state_machine;      ///< Runtime state machine presentation
    };

    #define NEXT_STATE_NOJUMP -1
    #define NEXT_STATE_COUNT -2
    #define NEXT_STATE_UNDEFINED -3
    #define NULL_ACTION -1

} // namespace sea

#endif // #if !defined( __sea_sm_engine_h__ )
